﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AutoBinding.cs" company="">
//   
// </copyright>
// <summary>
//   The auto binding.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Bindings
{
    using System.Reflection;

    /// <summary>
    /// The auto binding.
    /// </summary>
    /// <typeparam name="T1">
    /// </typeparam>
    /// <typeparam name="T2">
    /// </typeparam>
    public class AutoBinding<T1, T2> : Binding<T1, T2>
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="AutoBinding{T1,T2}"/> class.
        /// </summary>
        /// <param name="service">
        /// The service. 
        /// </param>
        /// <param name="obj1">
        /// The obj 1. 
        /// </param>
        /// <param name="obj2">
        /// The obj 2. 
        /// </param>
        public AutoBinding(IBindService service, T1 obj1, T2 obj2)
            : base(service, obj1, obj2)
        {
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        ///   The bind.
        /// </summary>
        public override void Bind()
        {
            base.Bind();
            var type1 = this.Object1.GetType();
            var type2 = this.Object2.GetType();
            var properties1 = type1.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            var properties2 = type2.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var property1 in properties1)
            {
                foreach (var property2 in properties2)
                {
                    if (property1.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }

                    if (property2.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }

                    if (!this.CanBindProperties(property1, property2))
                    {
                        continue;
                    }

                    var value1 = property1.GetValue(this.Object1, null);

                    // TODO refactor binding for primitive types
                    if (property1.PropertyType.IsPrimitive
                        || property1.PropertyType == typeof(string) && property2.PropertyType.IsPrimitive
                        || property2.PropertyType == typeof(string))
                    {
                        property2.SetValue(this.Object2, value1, null);
                    }
                    else
                    {
                        var value2 = property2.GetValue(this.Object2, null);
                        if (value1 != null && value2 != null)
                        {
                            this.Bind(value1, value2);
                        }
                    }
                }
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// The can bind properties.
        /// </summary>
        /// <param name="property1">
        /// The property 1. 
        /// </param>
        /// <param name="property2">
        /// The property 2. 
        /// </param>
        /// <returns>
        /// The <see cref="bool"/> . 
        /// </returns>
        protected virtual bool CanBindProperties(PropertyInfo property1, PropertyInfo property2)
        {
            if (property1.Name == property2.Name)
            {
                return false;
            }

            return false;
        }

        #endregion
    }
}